// #ifdef ZQ_SIMULATOR

#include <stdint.h>
#include "drv_ble_cfg.h"
#include "CH58x_common.h"
#include "zqm_global.h"
#include "zqm_module.h"
#include "task_ble.h"

#define BLE_CONN_INTERVAL_MIN    8      // default Minimum/Maximum connection interval (units of 1.25ms, 10=12.5ms)
#define BLE_CONN_INTERVAL_MAX    20
#define BLE_CONN_SLAVE_LATENCY   0      // Slave latency to use parameter update
#define BLE_CONN_TIMEOUT         100    // Supervision timeout value (units of 10ms, 100=1s)
// Simple BLE Peripheral Task Events
#define SBP_START_DEVICE_EVT        0x0001
#define SBP_PERIODIC_EVT            0x0002
#define SBP_ADV_IN_CONNECTION_EVT   0x0004
#define SBP_PARAM_UPDATE_EVT        0x0008
#define BLE_EXCH_SEND_EVT           0x0010
// Parameter update delay
#define SBP_PARAM_UPDATE_DELAY               6400

static uint8_t ble_gap_role_state = GAPROLE_INIT;

static bool init_done = false;
bool BleExchIsInit(void)
{
    return init_done;
}

#if ((!ZQ_SIMULATOR) && (ZQ_BLE_PLATFORM == 582))
static uint8_t TmosBleExch_TID; // Task ID for internal task/event processing
static ZqFifoBuf * ble_exch_rx_buf;
static ZqFifoBuf * ble_exch_tx_buf;

static uint8 IsBleExchNotifyReady(uint16 connHandle);
static int BleExchNotify(uint8_t *data, uint16_t len);

// 初始化蓝牙库 -----------------------------------------------------------------------------------------------
static __attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];

static uint32_t BleReadFlash(uint32_t addr, uint32_t num, uint32_t *pBuf)
{
    EEPROM_READ(addr, pBuf, num * 4);
    return 0;
}
static uint32_t BleWriteFlash(uint32_t addr, uint32_t num, uint32_t *pBuf)
{
    EEPROM_ERASE(addr, num * 4);
    EEPROM_WRITE(addr, pBuf, num * 4);
    return 0;
}
static void BleCalibrationLSI(void)
{
    Calibration_LSI(Level_64);
}
static uint16_t BleGetInterTempValue(void)
{
    uint8_t  sensor, channel, config, tkey_cfg;
    uint16_t adc_data;

    tkey_cfg = R8_TKEY_CFG;
    sensor = R8_TEM_SENSOR;
    channel = R8_ADC_CHANNEL;
    config = R8_ADC_CFG;
    ADC_InterTSSampInit();
    R8_ADC_CONVERT |= RB_ADC_START;
    while(R8_ADC_CONVERT & RB_ADC_START);
    adc_data = R16_ADC_DATA;
    R8_TEM_SENSOR = sensor;
    R8_ADC_CHANNEL = channel;
    R8_ADC_CFG = config;
    R8_TKEY_CFG = tkey_cfg;
    return (adc_data);
}
static void BleLibInit(void)
{
    uint8_t     i;
    bleConfig_t cfg;
    // SysTick_Config(SysTick_LOAD_RELOAD_Msk);
    // PFIC_DisableIRQ(SysTick_IRQn);
    tmos_memset(&cfg, 0, sizeof(bleConfig_t));
    cfg.MEMAddr = (uint32_t)MEM_BUF;
    cfg.MEMLen = (uint32_t)BLE_MEMHEAP_SIZE;
    cfg.BufMaxLen = (uint32_t)BLE_BUFF_MAX_LEN;
    cfg.BufNumber = (uint32_t)BLE_BUFF_NUM;
    cfg.TxNumEvent = (uint32_t)BLE_TX_NUM_EVENT;
    cfg.TxPower = (uint32_t)BLE_TX_POWER;
    // 开启SNV功能，用于储存绑定信息
    cfg.SNVAddr = (uint32_t)BLE_SNV_ADDR;
    cfg.readFlashCB = BleReadFlash;
    cfg.writeFlashCB = BleWriteFlash;
    // RTC时钟选择，如包含主机角色必须使用外部32K( 0 外部(32768Hz)，默认:1：内部(32000Hz)，2：内部(32768Hz)
    cfg.SelRTCClock = (uint32_t)CLK_OSC32K;
    cfg.ConnectNumber = (PERIPHERAL_MAX_CONNECTION & 3) | (CENTRAL_MAX_CONNECTION << 2);
    cfg.srandCB = SYS_GetSysTickCnt;
    // 根据温度变化校准RF和内部RC( 大于7摄氏度 )
    cfg.tsCB = BleGetInterTempValue; // 根据温度变化校准RF和内部RC( 大于7摄氏度 )
    // 内部32K时钟校准
    cfg.rcCB = BleCalibrationLSI; // 内部32K时钟校准

    uint8_t MacAddr[6];
    GetMACAddress(MacAddr);
    for(i = 0; i < 6; i++) cfg.MacAddr[i] = MacAddr[i]; // 使用芯片mac地址
    i = BLE_LibInit(&cfg);
    if(BLE_LibInit(&cfg) != 0) {
        ZQLOG("LIB init error code: %x ...", i);
        while(1);
    }
}

// 初始化RTC/timer -----------------------------------------------------------------------------------------------
#define TMOS_TIME_CALI_EVENT    0x2000
static tmosEvents TmosTimeCaliTask(tmosTaskID task_id, tmosEvents events)
{
    if(events & SYS_EVENT_MSG) // 系统消息, 此App无特殊处理
    { 
        uint8 *pMsg = tmos_msg_receive(task_id);
        if(pMsg) tmos_msg_deallocate(pMsg);
        return (events ^ SYS_EVENT_MSG);
    }
    if(events & TMOS_TIME_CALI_EVENT)
    {
        BLE_RegInit();                                                  // 校准RF
        BleCalibrationLSI(); // 校准内部RC
        tmos_start_task(task_id, TMOS_TIME_CALI_EVENT, MS1_TO_SYSTEM_TIME(BLE_CALIBRATION_PERIOD));
        return events ^ TMOS_TIME_CALI_EVENT;
    }
    return 0;
}
void BleTimerInit(void)
{
    // 校时
    sys_safe_access_enable();
    R8_CK32K_CONFIG &= ~(RB_CLK_OSC32K_XT | RB_CLK_XT32K_PON);
    sys_safe_access_enable();
    R8_CK32K_CONFIG |= RB_CLK_INT32K_PON;
    sys_safe_access_disable();
    BleCalibrationLSI();
    //RTC时钟初始化当前时间
    // RTC_InitTime(2020, 1, 1, 0, 0, 0);
    // 初始化Tmos系统时钟
    TMOS_TimerInit(0);
    // 添加定时校时任务
    tmosTaskID TmosTimeCali = TMOS_ProcessEventRegister(TmosTimeCaliTask); // 向tmos添加校准任务
    tmos_start_task(TmosTimeCali, TMOS_TIME_CALI_EVENT, MS1_TO_SYSTEM_TIME(BLE_CALIBRATION_PERIOD)); // 启动校准任务，单次校准耗时小于10ms
}

// Gap functions -----------------------------------------------------------------------------------------------
typedef struct {
    uint16_t handle; // Connection handle of current connection
    uint16_t interval;
    uint16_t slave_latency;
    uint16_t timeout;
} BlePeripheralConnItem;
static BlePeripheralConnItem ble_cur_conn;     // 当前连接的客户端
// GAP - Advertisement data (max size = 31 bytes)
static uint8_t advertData[] = {
    // 广播类型项长度
    0x02, // length of this data
    // 广播类型项flag
    GAP_ADTYPE_FLAGS,
    // 广播类型: 不支持 BR/EDR 有限发现模式, 注意：GAP_ADTYPE_FLAGS_LIMITED模式缺省3分钟关闭广播
    // GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED | GAP_ADTYPE_FLAGS_LIMITED,
    GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED | GAP_ADTYPE_FLAGS_GENERAL,
    // 自定义项长度
    0x1A,
    // 自定义项flag
    0xFF, 
    // 自定义项: 1. 厂商代码
    0x4c, 0x00, 0x02, 0x15,
    // 自定义项: 2. default UUID
    0xAB, 0x81, 0x90, 0xD5, 0xD1, 0x1E, 0x49, 0x41, 0xAC, 0xC4, 0x42, 0xF3, 0x05, 0x10, 0xB4, 0x08,
    // 自定义项: 3. default Major
    0x27, 0x73,
    // 自定义项: 4. default Minor, 程序会复制ble mac地址的最后两位作为default Minor
    0x00, 0x00,
    // 自定义项: 5. default 信号强度，目前写死
    0xB6
};
// GAP - SCAN RSP data (max size = 31 bytes)
static uint8_t scanRspData[] = {
    // complete name
    0x0c,                                 // length of this data
    GAP_ADTYPE_LOCAL_NAME_COMPLETE, 
    0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x65, 0x72, // "broadcaster"
    // connection interval range
    0x05, // length of this data
    GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
    LO_UINT16(BLE_CONN_INTERVAL_MIN), // 100ms
    HI_UINT16(BLE_CONN_INTERVAL_MIN),
    LO_UINT16(BLE_CONN_INTERVAL_MAX), // 1s
    HI_UINT16(BLE_CONN_INTERVAL_MAX),
    // Tx power level
    0x02,                     // length of this data
    GAP_ADTYPE_POWER_LEVEL, 
    0                           // 0dBm
};
// gap callback functions
static void ble_gap_notify_cb(gapRole_States_t newState, gapRoleEvent_t *pEvent);
static void ble_gap_rssi_cb(uint16 connHandle, int8 rssi);
static void ble_gap_param_update_cb(uint16 connHandle, uint16 connInterval, uint16 connSlaveLatency, uint16 connTimeout);
// GAP Role Callbacks
static gapRolesCBs_t ble_gap_role_cbs = {
    ble_gap_notify_cb, // Profile State Change Callbacks
    ble_gap_rssi_cb,              // When a valid RSSI is read from controller (not used by application)
    ble_gap_param_update_cb
};
// Broadcast Callbacks
static gapRolesBroadcasterCBs_t ble_broadcaster_cbs = {
    NULL, // Not used in peripheral role
    NULL  // Receive scan request callback
};
// GAP Bond Manager Callbacks
static gapBondCBs_t ble_bond_man_cbs = {
    NULL, // Passcode callback (not used by application)
    NULL  // Pairing / Bonding state Callback (not used by application)
};
// gap fuctions
static void BleLinkEstablished(gapRoleEvent_t *pEvent)
{
    gapEstLinkReqEvent_t *event = (gapEstLinkReqEvent_t *)pEvent;

    if(ble_cur_conn.handle == GAP_CONNHANDLE_INIT)  // See if already connected, this app only support 1 connection
    {
        ble_cur_conn.handle = event->connectionHandle;
        ble_cur_conn.interval = event->connInterval;
        ble_cur_conn.slave_latency = event->connLatency;
        ble_cur_conn.timeout = event->connTimeout;
        // Set timer for param update event
        tmos_start_task(TmosBleExch_TID, SBP_PARAM_UPDATE_EVT, SBP_PARAM_UPDATE_DELAY);
        ZQLOG("Conn %x - Int %x - lat %x - tout %x \n", event->connectionHandle, event->connInterval, event->connLatency, event->connTimeout);
    }
}
static void BleLinkTerminated(gapRoleEvent_t *pEvent)
{
    gapTerminateLinkEvent_t *event = (gapTerminateLinkEvent_t *)pEvent;
    if(event->connectionHandle == ble_cur_conn.handle)
    {
        // clear connection item
        ble_cur_conn.handle = GAP_CONNHANDLE_INIT;
        ble_cur_conn.interval = ble_cur_conn.slave_latency = ble_cur_conn.timeout = 0;
        // Restart advertising
        uint8 advertising_enable = TRUE;
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8), &advertising_enable);
    }
}

static void ble_gap_notify_cb(gapRole_States_t newState, gapRoleEvent_t *pEvent)
{
    ble_gap_role_state = (uint8_t)(newState & GAPROLE_STATE_ADV_MASK);
    switch(ble_gap_role_state)
    {
        case GAPROLE_STARTED:
            ZQLOG("Initialized...");
            break;
        case GAPROLE_ADVERTISING:
            ZQLOG("Advertising... opcode = %02x", pEvent->gap.opcode);
            if(pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT) {
                BleLinkTerminated(pEvent);
                zy_st.ble = 0;
            }
            else
                zy_st.ble = 1;
            break;
        case GAPROLE_CONNECTED:
            ZQLOG("Connected... opcode = %02x", pEvent->gap.opcode);
            if(pEvent->gap.opcode == GAP_LINK_ESTABLISHED_EVENT) {
                BleLinkEstablished(pEvent);
                ZQLOG("Connected...");
            }
            // GAPRole_PeripheralConnParamUpdateReq(ble_cur_conn.handle, 80, 80, 0, 0x1f4, TmosBleExch_TID); // TODO 测试代码，更新参数
            break;
        case GAPROLE_CONNECTED_ADV:
            ZQLOG("Connected Advertising...");
            break;

        case GAPROLE_WAITING:
            ZQLOG("Waiting... opcode = %02x", pEvent->gap.opcode);
            if(pEvent->gap.opcode == GAP_END_DISCOVERABLE_DONE_EVENT) {
                ZQLOG("Waiting for advertising..\n");
            }
            else if(pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT) {
                BleLinkTerminated(pEvent);
                ZQLOG("Disconnected.. Reason:%x\n", pEvent->linkTerminate.reason);
            }
            else if(pEvent->gap.opcode == GAP_LINK_ESTABLISHED_EVENT) {
                if(pEvent->gap.hdr.status != SUCCESS)
                    ZQLOG("Waiting for advertising..\n");
                else
                    ZQLOG("Error..\n");
            }
            else {
                ZQLOG("Error..%x\n", pEvent->gap.opcode);
            }
            break;
        case GAPROLE_ERROR:
            ZQLOG("Error..\n");
            break;
        default:
            break;
    }
}
static void ble_gap_rssi_cb(uint16 connHandle, int8 rssi)
{
    ZQLOG("RSSI -%d dB Conn  %x \n", -rssi, connHandle);
}
static void ble_gap_param_update_cb(uint16 connHandle, uint16 connInterval, uint16 connSlaveLatency, uint16 connTimeout)
{
    if(connHandle == ble_cur_conn.handle)
    {
        ble_cur_conn.interval = connInterval;
        ble_cur_conn.slave_latency = connSlaveLatency;
        ble_cur_conn.timeout = connTimeout;
        ZQLOG("Update %x - Int %x - lat %x - tout %x \n", connHandle, connInterval, connSlaveLatency, connTimeout);
    }
}

// main ble task -----------------------------------------------------------------------------------------------
uint16 TmosBleExch_TIDTask(uint8 task_id, uint16 events)
{
    if(events & SYS_EVENT_MSG) { // 系统消息, 此App无特殊处理
        uint8 *pMsg = tmos_msg_receive(task_id);
        if(pMsg) tmos_msg_deallocate(pMsg);
        return (events ^ SYS_EVENT_MSG);
    }
    if(events & SBP_START_DEVICE_EVT) {
        // Start the Device
        GAPRole_PeripheralStartDevice(TmosBleExch_TID, &ble_bond_man_cbs, &ble_gap_role_cbs);
        return (events ^ SBP_START_DEVICE_EVT);
    }
    if(events & SBP_PARAM_UPDATE_EVT) {
        // Send connect param update request
        GAPRole_PeripheralConnParamUpdateReq(ble_cur_conn.handle, BLE_CONN_INTERVAL_MIN, BLE_CONN_INTERVAL_MAX, 
            BLE_CONN_SLAVE_LATENCY, BLE_CONN_TIMEOUT, TmosBleExch_TID);
        return (events ^ SBP_PARAM_UPDATE_EVT);
    }
    if(events & BLE_EXCH_SEND_EVT) {
        static uint8_t ble_exch_wait_more_data = 0;
        //notify is not enabled, discard data
        if(!IsBleExchNotifyReady(ble_cur_conn.handle))
            ZqFifoBufFlush(ble_exch_tx_buf, 0xffff);
        uint16_t pkg_len = ATT_GetMTU(ble_cur_conn.handle) - 3;
        uint16_t len = ble_exch_tx_buf->len;
        uint8_t *data = ble_exch_tx_buf->data;

        if(len > 0) {
            // 如果缓存里的数据量小于一个包, 等待最多10个周期去凑更多的数据。
            if (len >= pkg_len) {
                len = pkg_len;
                ble_exch_wait_more_data = 10;
            }
            if((++ble_exch_wait_more_data) > 10)
            {
                if(BleExchNotify(data, len) == 0) { // no error
                    ZqFifoBufFlush(ble_exch_tx_buf, len);
                    ble_exch_wait_more_data = 0;
                    // tmos_start_task(TmosBleExch_TID, BLE_EXCH_SEND_EVT, 4);
                }
                // else // error， retry
                //     tmos_start_task(TmosBleExch_TID, BLE_EXCH_SEND_EVT, 2);
            }

        }
        tmos_start_task(TmosBleExch_TID, BLE_EXCH_SEND_EVT, 4);
        return (events ^ BLE_EXCH_SEND_EVT);
    }
    // Discard unknown events
    return 0;
}


// GATT profile -----------------------------------------------------------------------------------------------
// 1. define GATT profile attribute table
// ble_uart GATT Profile Service UUID
const uint8_t ble_exch_service_uuid[ATT_BT_UUID_SIZE] = {0xf0, 0xff};
// Characteristic rx uuid
const uint8_t ble_exch_char_tx_uuid[ATT_BT_UUID_SIZE] = {0xf1, 0xff};
// Characteristic tx uuid
const uint8_t ble_exch_char_rx_uuid[ATT_BT_UUID_SIZE] = {0xf2, 0xff};
// define ble exchange data Profile Service attribute, uuid: 0xfff0
static const gattAttrType_t ble_exch_service = {ATT_BT_UUID_SIZE, ble_exch_service_uuid};
// Characteristic tx Value
static uint8_t ble_exch_char_tx_value[1] = {0};
// Characteristic tx Value
static uint8_t ble_exch_char_tx_prop = GATT_PROP_NOTIFY; // tx properties
// Simple Profile Characteristic 2 User Description
static gattCharCfg_t ble_exch_char_tx_cccd[4];
// Characteristic rx Value
static uint8_t ble_exch_char_rx_value[1];
// Characteristic tx Value
static uint8_t ble_exch_char_rx_prop = GATT_PROP_WRITE_NO_RSP; // rx properties
// Profile Attributes - Table
static gattAttribute_t ble_exch_profile_tb[] = {
    // Simple Profile Service
    {
        {ATT_BT_UUID_SIZE, primaryServiceUUID}, /* type */ // primary service
        GATT_PERMIT_READ,                       /* permissions */
        0,                                      /* handle */
        (uint8_t *)&ble_exch_service            /* pValue */ // ble_exch_Service
    },
    // Characteristic tx Declaration
    {
        {ATT_BT_UUID_SIZE, characterUUID},      // characteristic declareation uuid
        GATT_PERMIT_READ,
        0,
        &ble_exch_char_tx_prop
    },
    // Characteristic tx Value
    {
        {ATT_BT_UUID_SIZE, ble_exch_char_tx_uuid},
        0,
        0,
        ble_exch_char_tx_value
    },
    // Characteristic tx User Description
    {
        {ATT_BT_UUID_SIZE, clientCharCfgUUID},
        GATT_PERMIT_READ | GATT_PERMIT_WRITE,
        0,
        (uint8 *)ble_exch_char_tx_cccd
    },
    // Characteristic rx Declaration
    {
        {ATT_BT_UUID_SIZE, characterUUID},      // characteristic declareation uuid
        GATT_PERMIT_READ,
        0,
        &ble_exch_char_rx_prop
    },
    // Characteristic rx Value 1
    {
        {ATT_BT_UUID_SIZE, ble_exch_char_rx_uuid},
        GATT_PERMIT_WRITE,
        0,
        ble_exch_char_rx_value
    },
};

// GATT profile services callback functions
static bStatus_t ble_exch_attr_read_cb(uint16 connHandle, gattAttribute_t *pAttr, uint8 *pValue, uint16 *pLen, uint16 offset, uint16 maxLen, uint8 method);
static bStatus_t ble_exch_attr_write_cb(uint16 connHandle, gattAttribute_t *pAttr, uint8 *pValue, uint16 len, uint16 offset, uint8 method);
static void ble_exch_conn_cb(uint16 connHandle, uint8 changeType);
gattServiceCBs_t ble_uart_ProfileCBs = {
    ble_exch_attr_read_cb,  // Read callback function pointer
    ble_exch_attr_write_cb, // Write callback function pointer
    NULL                  // Authorization callback function pointer
};
static bStatus_t ble_exch_attr_read_cb(uint16 connHandle, gattAttribute_t *pAttr, uint8 *pValue, uint16 *pLen, uint16 offset, uint16 maxLen, uint8 method)
{
    bStatus_t status = SUCCESS;
    if(pAttr->type.len != ATT_BT_UUID_SIZE) return status; // only deal with 16-bit UUID
    uint16 uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
    if(uuid == GATT_CLIENT_CHAR_CFG_UUID) { // only deal with Characteristic tx user description client config
        *pLen = 2;
        tmos_memcpy(pValue, pAttr->pValue, 2);
    }
    return status;
}
static bStatus_t ble_exch_attr_write_cb(uint16 connHandle, gattAttribute_t *pAttr, uint8 *pValue, uint16 len, uint16 offset, uint8 method)
{
    bStatus_t status = SUCCESS;
    // If attribute permissions require authorization to write, return error
    if(gattPermitAuthorWrite(pAttr->permissions))
        return (ATT_ERR_INSUFFICIENT_AUTHOR);
    if(pAttr->type.len != ATT_BT_UUID_SIZE) return status; // only deal with 16-bit UUID
    uint16 uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
    if(uuid == GATT_CLIENT_CHAR_CFG_UUID)
    {
        status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len, offset, GATT_CLIENT_CFG_NOTIFY);
        if(status == SUCCESS) 
            ZQLOG("%02x:bleuart_EVT_TX_NOTI_ENABLED: %d", connHandle, BUILD_UINT16(pValue[0], pValue[1]));
    }
    //  UUID
    if(pAttr->handle == ble_exch_profile_tb[5].handle)
    {
        ZqFifoBufWrite(ble_exch_rx_buf, pValue, len);
    }
    return (status);
}

static void ble_exch_conn_cb(uint16 connHandle, uint8 changeType)
{
    // Make sure this is not loopback connection
    if(connHandle != LOOPBACK_CONNHANDLE) {
        // Reset Client Char Config if connection has dropped
        if((changeType == LINKDB_STATUS_UPDATE_REMOVED) 
            || ((changeType == LINKDB_STATUS_UPDATE_STATEFLAGS) && (!linkDB_Up(connHandle))))
            GATTServApp_InitCharCfg(connHandle, ble_exch_char_tx_cccd);
    }
}
static uint8 IsBleExchNotifyReady(uint16 connHandle)
{
    return (GATT_CLIENT_CFG_NOTIFY == GATTServApp_ReadCharCfg(connHandle, ble_exch_char_tx_cccd));
}
static int BleExchNotify(uint8_t *data, uint16_t len)
{
    attHandleValueNoti_t noti;
    noti.len = len;
    noti.handle = ble_exch_profile_tb[2].handle;
    noti.pValue = GATT_bm_alloc(ble_cur_conn.handle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0);
    if(noti.pValue) {
        tmos_memcpy(noti.pValue, data, noti.len);
        if(GATT_Notification(ble_cur_conn.handle, &noti, FALSE) != SUCCESS)
            GATT_bm_free((gattMsg_t *)&noti, ATT_HANDLE_VALUE_NOTI);
        else
            return 0;
    }
    return -1;
}

static uint8_t ble_adv_event_type = GAP_ADTYPE_ADV_NONCONN_IND;
// Ble Peripheral 功能初始化
static void BlePeripheralInit(void)
{
    TmosBleExch_TID = TMOS_ProcessEventRegister(TmosBleExch_TIDTask); // 向Tmos添加ble任务

    // Setup adv and scan parameters
    {
        // enable advertising
        uint8_t initial_advertising_enable = TRUE;  
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);
        GAPRole_SetParameter(GAPROLE_ADV_EVENT_TYPE, sizeof(uint8_t), &ble_adv_event_type);
        // set advertising interval and connection interval
        uint16_t advInt = 160; // advertising interval when device is discoverable (units of 625us, min is 160=100ms)
        GAP_SetParamValue(TGAP_DISC_ADV_INT_MIN, advInt);
        GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, advInt);
        GAP_SetParamValue(TGAP_CONN_EST_SUPERV_TIMEOUT, 2000);
        GAP_SetParamValue(TGAP_CONN_EST_INT_MIN, 80);
        GAP_SetParamValue(TGAP_CONN_EST_INT_MAX, 80);
        uint16_t desired_min_interval = 6;          // Minimum connection interval (units of 1.25ms, 6=7.5ms)
        uint16_t desired_max_interval = 1000;       // Maximum connection interval (units of 1.25ms, 100=125ms)
        GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16_t), &desired_min_interval);
        GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16_t), &desired_max_interval);
        // set adverise data
        memcpy(advertData+9, m0_diag.ble_uuid, 16); 
        memcpy(advertData+25, m0_diag.ble_major, 2); 
        memcpy(advertData+27, m0_diag.ble_minor, 2); 
        GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);
        // set scan response data
        GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), scanRspData);
    }

    // Setup the GAP Bond Manager
    {
        uint32_t passkey = 0; // passkey "000000"
        uint8_t  pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
        uint8_t  mitm = TRUE;
        uint8_t  bonding = TRUE;
        uint8_t  ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
        GAPBondMgr_SetParameter(GAPBOND_PERI_DEFAULT_PASSCODE, sizeof(uint32_t), &passkey);
        GAPBondMgr_SetParameter(GAPBOND_PERI_PAIRING_MODE, sizeof(uint8_t), &pairMode);
        GAPBondMgr_SetParameter(GAPBOND_PERI_MITM_PROTECTION, sizeof(uint8_t), &mitm);
        GAPBondMgr_SetParameter(GAPBOND_PERI_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
        GAPBondMgr_SetParameter(GAPBOND_PERI_BONDING_ENABLED, sizeof(uint8_t), &bonding);
    }

    static uint8 attDeviceName[GAP_DEVICE_NAME_LEN] = "Broadcaster";
    // Set the GAP Characteristics
    GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName);
    // Initialize GATT attributes table 
    {
        GGS_AddService(GATT_ALL_SERVICES);              // call GAP GATT Service App to add service
        GATTServApp_AddService(GATT_ALL_SERVICES);      // call GATT server to add services
        GATTServApp_InitCharCfg(INVALID_CONNHANDLE, ble_exch_char_tx_cccd); // Clear all connection. INVALID_CONNHANDLE = 0xffff -- for all connections
        linkDB_Register(ble_exch_conn_cb);              // Register with Link DB to receive link status change callback
        // Register GATT attribute list and CBs with GATT Server App
        GATTServApp_RegisterService(ble_exch_profile_tb, GATT_NUM_ATTRS(ble_exch_profile_tb), GATT_MAX_ENCRYPT_KEY_SIZE, &ble_uart_ProfileCBs);
        // ble_uart_AppCBs = on_bleuartServiceEvt;
    }

    // Init Connection Item
    {
        ble_cur_conn.handle = GAP_CONNHANDLE_INIT;
        ble_cur_conn.interval = ble_cur_conn.slave_latency = ble_cur_conn.timeout = 0;
    }

    // Register receive scan request callback
    GAPRole_BroadcasterSetCB(&ble_broadcaster_cbs);

    // start ble 
    tmos_set_event(TmosBleExch_TID, SBP_START_DEVICE_EVT);
}

// force = 0: start ble only when ZQ_BLE_PLATFORM == 582; force = 1: force to start ble
void BleExchInit(uint8_t force)
{
    if(ZQ_BLE_PLATFORM != 582 && force == 0)
        return;
    if(!init_done || force == 1)
    {
        init_done = true;
        ble_exch_rx_buf = ZqFifoBufCreate(1024, NULL);
        ble_exch_tx_buf = ZqFifoBufCreate(1024, NULL);
        BleLibInit();                   // 初始化蓝牙库; = CH58X_BLEInit()
        BleTimerInit();                 // 初始化RTC; = HAL_TimeInit()
        GAPRole_PeripheralInit();       // Ble Peripheral 角色初始化; 
        BlePeripheralInit();            // Ble Peripheral 功能初始化
    }
}
void BleAdvConnectableSwitch(void)
{
    uint8_t initial_advertising_enable = FALSE;  
    GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);
    TMOS_SystemProcess();
    ble_adv_event_type = (ble_adv_event_type == GAP_ADTYPE_ADV_IND) ? GAP_ADTYPE_ADV_NONCONN_IND : GAP_ADTYPE_ADV_IND;
    GAPRole_SetParameter(GAPROLE_ADV_EVENT_TYPE, sizeof(uint8_t), &ble_adv_event_type);
    TMOS_SystemProcess();
    if(ZQ_BLE_PLATFORM == 582 || ble_adv_event_type == GAP_ADTYPE_ADV_IND) { // 只有项目需要蓝牙广播, 或者强制开启蓝牙dbg才启动广播
        initial_advertising_enable = TRUE;
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);
        TMOS_SystemProcess();
    }
}
uint8_t BleGetGapRoleState(void)
{
    return ble_gap_role_state;
}
void BleExchStart(void)
{

}
void BleExchSend(uint8_t *buf, uint16_t len)
{
    ZqFifoBufWrite(ble_exch_tx_buf, buf, len);
    tmos_start_task(TmosBleExch_TID, BLE_EXCH_SEND_EVT, 2);
}
void BleExchRecv(void (*rx_cb)(ZqCommPkg* pkg))
{
    // // TODO 测试代码
    // char tmp[100];
    // if(ble_exch_rx_buf->len > 0 && ble_exch_rx_buf->len < 99){
    //     memcpy(tmp, ble_exch_rx_buf->data, ble_exch_rx_buf->len);
    //     tmp[ble_exch_rx_buf->len] = 0;
    //     ZQLOG("%s", tmp); 
    //     ZqFifoBufFlush(ble_exch_rx_buf, 0xffff);
    //     return;
    // }

    uint8_t* data = ble_exch_rx_buf->data;
    uint16_t data_len = ble_exch_rx_buf->len;
    uint16_t step = 0;
    ZqCommPkg* pkg;

    for (; step < data_len; step += pkg->len) {
        if ((data_len - step) < sizeof(ZqCommPkg)) break; // wait more data
        pkg = (ZqCommPkg*)(data + step);
        if (pkg->flag != COMM_PKG_HEAD_FLAG || pkg->len > ble_exch_rx_buf->max_size || pkg->len < sizeof(ZqCommPkg)) {// 标志出错或长度出错, discard all data
            step = 0xffff;
            break;
        }
        if (pkg->len > (data_len - step)) break; // wait more data
        if (ZqGetChecksum(data, pkg->len) != 0) { // checksum error
            step = 0xffff;
            break;
        }
        rx_cb(pkg);
    }

    if (step > 0) // there are discard data, need to djust the data pointer of receive buffer
        ZqFifoBufFlush(ble_exch_rx_buf, step);
}
void BleExchClose(void)
{
    //获取当前广播状态
    uint8_t adv_status;
    GAPRole_GetParameter(GAPROLE_ADVERT_ENABLED, &adv_status);
    
    //开启广播
    //对应状态上报:GAPROLE_ADVERTISING
    uint8_t advertising_enable = true;
    GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8_t ), &advertising_enable );
    
    //关闭广播
    //  对应的状态上报:
    // :GAPROLE_WAITING
    // :pEvent->gap.opcode == GAP_END_DISCOVERABLE_DONE_EVENT
    if(adv_status != 0) {
        adv_status = 0;
        GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8_t ), &adv_status);
    }
    
 
}

#else // !ZQ_SIMULATOR
void BleExchInit(uint8_t force)
{
}
void BleAdvConnectableSwitch(void)
{
}
uint8_t BleGetGapRoleState(void)
{
    return ble_gap_role_state;
}
void BleExchStart(void)
{

}
void BleExchSend(uint8_t* buf, uint16_t len)
{
}
void BleExchRecv(void (*rx_cb)(ZqCommPkg* pkg))
{
}
void BleExchClose(void)
{

}

#endif // !ZQ_SIMULATOR
